package com.jky.filesystem;

import com.jky.filesystem.Data.*;
import com.jky.filesystem.devices.SelectDeviceDialog;
import com.jky.filesystem.utils.PermissionsUtils;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.IAbilityConnection;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.utils.Color;
import ohos.bundle.AbilityInfo;
import ohos.bundle.ElementName;
import ohos.data.distributed.common.KvManagerConfig;
import ohos.data.distributed.common.KvManagerFactory;
import ohos.data.distributed.common.KvStoreException;
import ohos.distributedschedule.interwork.DeviceInfo;
import ohos.distributedschedule.interwork.DeviceManager;
import ohos.event.commonevent.CommonEventData;
import ohos.event.commonevent.CommonEventManager;
import ohos.event.notification.NotificationHelper;
import ohos.event.notification.NotificationRequest;
import ohos.event.notification.NotificationSlot;
import ohos.rpc.*;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.utils.net.Uri;
import ohos.utils.zson.ZSONObject;

import java.util.*;

public class BallServiceAbility extends Ability {
    private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "测试小球");

    private MyRemote remote = new MyRemote();

    private MyRemoteProxy proxy;

    private boolean isLocal = true; //是否是本地端

    private String localDeviceId;  //当前设备的ID

    private IAbilityConnection conn;  //ability连接的回调

    private String remoteDeviceId;  //调起此ability的设备ID

    private boolean isConnected = false;  //是否与ability连接

    private boolean isMainStart = false;  //mainAbility是否已启动

    @Override
    public void onStart(Intent intent) {
        HiLog.error(LABEL_LOG, "BallServiceAbility::onStart");
        super.onStart(intent);
        HiLog.info(LABEL_LOG,ZSONObject.toZSONString(intent));
        PermissionsUtils.requestRemotePermission(this);
        initService(intent);
    }

    //初始化本地参数
    private void initService(Intent intent) {
        localDeviceId = KvManagerFactory.getInstance().createKvManager(new KvManagerConfig(this)).getLocalDeviceInfo().getId();
    }

    //当此设备是被调起的ability时，初始化其他设备的Ability
    private void initRemoteProxy(MessageParcel data) {
        if(!isLocal) {
            HiLog.info(LABEL_LOG,"不是本地，接收到的设备ID：" + remoteDeviceId);
            connectRemotePa(remoteDeviceId, MyRemoteProxy.REQUEST_SEND_DATA, data);
        }
    }

    private void connectRemotePa(String deviceId, int requestType, MessageParcel data) {
        if(!deviceId.isEmpty()) {
            Intent connectPaIntent = new Intent();
            Operation operation = new Intent.OperationBuilder().withDeviceId(deviceId)
                    .withBundleName(getBundleName())
                    .withAbilityName(CommonData.ABILITY_BALL_SREVICE)
                    .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
                    .build();
            connectPaIntent.setParam(CommonData.KEY_REMOTE_DEVICEID, localDeviceId);
            connectPaIntent.setParam(CommonData.KEY_IS_LOCAL, isLocal);
            connectPaIntent.setOperation(operation);

            conn = new IAbilityConnection() {
                @Override
                public void onAbilityConnectDone(ElementName elementName, IRemoteObject remote, int resultCode) {
                    HiLog.info(LABEL_LOG, "onAbilityConnectDone......");
                    connectAbility(elementName, remote, requestType, data);
                }

                @Override
                public void onAbilityDisconnectDone(ElementName elementName, int resultCode) {
                    disconnectWithOther();
                    disconnectAbility(this);
                    HiLog.info(LABEL_LOG, "onAbilityDisconnectDone......" + resultCode);
                }
            };
            isConnected = getContext().connectAbility(connectPaIntent, conn);
            HiLog.info(LABEL_LOG, "连接结果：" + isConnected);
        }
    }

    private void connectAbility(ElementName elementName, IRemoteObject remote, int requestType, MessageParcel data) {
        proxy = new MyRemoteProxy(remote);
        if (proxy != null) {
            try {
                proxy.senDataToRemote(requestType, data);
            } catch (RemoteException e) {
                HiLog.error(LABEL_LOG, "onAbilityConnectDone RemoteException");
            }
        }
    }

    //与其他设备失去连接，将该信息返回前端（js）
    private void disconnectWithOther() {
        HiLog.error(LABEL_LOG,"disconnectWithOther");
        proxy = null;
        isConnected = false;
        DisconnectData disconnectData = new DisconnectData();
        disconnectData.setMethod(CommonData.JS_CALLBACK_CONNECT_FAIL);
        SendData sendData = new SendData();
        sendData.setMsg(ZSONObject.toZSONString(disconnectData));
        MessageParcel messageParcel = MessageParcel.create();
        messageParcel.writeString(ZSONObject.toZSONString(sendData));
        remote.startNotify(messageParcel);
    }


    class MyRemote extends RemoteObject implements IRemoteBroker {
        private static final int SUCCESS = 0;
        private static final int ERROR = 1;
        private static final int REQUEST_GET_DEVICE = 1;//获取设备列表
        private static final int REQUEST_CONNECT = 2;//启动另一台设备并连接
        private static final int REQUEST_SEND_MSG = 3;//向连接的设备发送信息
        private static final int REQUEST_SUBSCRIBE = 4;//订阅java
        private static final int REQUEST_UNSUBSCRIBE = 5;//取消订阅
        private static final int REQUEST_HIDE = 6;//app隐藏
        private static final int REQUEST_DESTORY = 7;//按下返回

        private Set<IRemoteObject> remoteObjectHandlers = new HashSet<IRemoteObject>();
        private Thread thread = null;

        MyRemote() {
            super("ServiceRemote");
        }

        @Override
        public IRemoteObject asObject() {
            return this;
        }

        @Override
        public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) {
            HiLog.info(LABEL_LOG,"java接收："+code);
            switch (code) {
                //获取设备
                case REQUEST_GET_DEVICE: {
                    List<DeviceInfo> deviceInfos = DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);
                    // 返回结果当前仅支持String，对于复杂结构可以序列化为ZSON字符串上报
                    Map<String, Object> result = new HashMap<String, Object>();
                    result.put("code", SUCCESS);
                    result.put("deviceInfo", deviceInfos);
                    reply.writeString(ZSONObject.toZSONString(result));
                    break;
                }
                //启动并连接远程FA
                case REQUEST_CONNECT: {
                    String dataStr = data.readString();
                    StartAbilityData startAbilityData = new StartAbilityData();
                    try {
                        startAbilityData = ZSONObject.stringToClass(dataStr, StartAbilityData.class);
                    }
                    catch (RuntimeException e) {

                    }
                    String getDeviceId = startAbilityData.getDeviceId();
                    MessageParcel messageParcel = MessageParcel.create();
                    messageParcel.writeString(startAbilityData.getJsRoute());
                    connectRemotePa(getDeviceId, MyRemoteProxy.REQUEST_START_ABILITY, messageParcel);
                    break;
                }
                //发送消息
                case REQUEST_SEND_MSG: {
//                    String getData = data.readString();
                    HiLog.info(LABEL_LOG, "发送：" + (proxy != null));

                    if (isConnected && proxy != null) {
                        try {
                            HiLog.info(LABEL_LOG, "senDataToRemote" + MyRemoteProxy.REQUEST_SEND_DATA);
                            proxy.senDataToRemote(MyRemoteProxy.REQUEST_SEND_DATA, data);
                        } catch (RemoteException e) {
                            HiLog.info(LABEL_LOG, "processEvent RemoteException");
                        }
                    } else {
                        HiLog.info(LABEL_LOG, "processEvent RemoteException Error");
                    }
                    break;
                }
                //开启订阅
                case REQUEST_SUBSCRIBE: {
                    Map<String, Object> result = new HashMap<String, Object>();
                    try {
                        isMainStart = true;
                        remoteObjectHandlers.add(data.readRemoteObject());
                        result.put("code", SUCCESS);
                        result.put("msg","订阅成功");
                        result.put("isLocal",isLocal);
                        reply.writeString(ZSONObject.toZSONString(result));
                    }
                    catch (KvStoreException e) {
                        result.put("code", ERROR);
                        result.put("msg","订阅失败");
                        reply.writeString(ZSONObject.toZSONString(result));
                        e.printStackTrace();
                    }

                    break;
                }
                // 取消订阅，置空对端的remoteHandler
                case REQUEST_UNSUBSCRIBE: {
                    Map<String, Object> result = new HashMap<String, Object>();
                    try {
                        // 如果仅支持单FA订阅，可直接置空：remoteObjectHandler = null;
                        remoteObjectHandlers.clear();
                        result.put("code", SUCCESS);
                        result.put("msg","取消订阅成功");
                        reply.writeString(ZSONObject.toZSONString(result));
                    }
                    catch (KvStoreException e) {
                        result.put("code", ERROR);
                        result.put("msg","取消订阅失败");
                        reply.writeString(ZSONObject.toZSONString(result));
                        e.printStackTrace();
                    }
                    break;
                }


                //启动MainAbility
                case MyRemoteProxy.REQUEST_START_ABILITY: {
                    String dataStr = data.readString();
                    SendData sendData = new SendData();
                    try {
                        sendData = ZSONObject.stringToClass(dataStr, SendData.class);
                    } catch (RuntimeException e) {
                        HiLog.error(LABEL_LOG, "convert failed.");
                    }
                    String getRemoteDeviceId = sendData.getRemoteDeviceId();
                    String route = sendData.getMsg();
                    HiLog.info(LABEL_LOG,"即将启动的js页面：" + route);
                    boolean getIsLocal = data.readBoolean();
                    remoteDeviceId = getRemoteDeviceId;
                    isLocal = getIsLocal;
                    HiLog.info(LABEL_LOG, "RemoteServiceAbility::isFirstStart:");
                    Intent secondIntent = new Intent();
                    Operation operation = new Intent.OperationBuilder()
                            .withDeviceId("")
                            .withBundleName(getBundleName())
                            .withAbilityName(CommonData.ABILITY_MAIN)
                            .withFlags(Intent.FLAG_ABILITY_FORWARD_RESULT)
                            .build();
                    secondIntent.setParam(CommonData.KEY_REMOTE_DEVICEID, localDeviceId);
                    secondIntent.setParam(CommonData.KEY_IS_LOCAL, isLocal);
                    secondIntent.setParam(CommonData.KEY_JS_ROUTE,route); //标识启动的页面
                    secondIntent.setOperation(operation);
                    try {
                        List<AbilityInfo> abilityInfoList = getBundleManager().queryAbilityByIntent(secondIntent, 0, 0);
                        //判断是否已经打开过ability
                        if (!isMainStart && abilityInfoList != null && !abilityInfoList.isEmpty()) {
                            startAbility(secondIntent);
                            Map<String, Object> result = new HashMap<String, Object>();
                            result.put("code", SUCCESS);
                            result.put("intent", secondIntent);
                            reply.writeString(ZSONObject.toZSONString(result));
                            HiLog.error(LABEL_LOG, "启动本地ability");
                        }
                        sendEvent(route);
                    } catch (RemoteException e) {
                        HiLog.error(LABEL_LOG, "启动本地ability失败");
                        reply.writeString("失败");
                        // 处理异常
                    }
                    initRemoteProxy(data);

                    reply.writeInt(SUCCESS);
                    HiLog.info(LABEL_LOG, "成功走过来了");
                    break;
                }
                //给JS发送消息
                case MyRemoteProxy.REQUEST_SEND_DATA: {
                    //这里不知道什么情况，如果不加的话会失效
                    String str = data.readString();
                    MessageParcel messageParcel = MessageParcel.create();
                    messageParcel.writeString(str);
                    startNotify(messageParcel);
                    break;
                }
                //通知js连接失败
//                case MyRemoteProxy.SEND_START_FILE: {
//                    ConnectFailData connectFailData = new ConnectFailData();
//                    connectFailData.setMethod(CommonData.JS_CALLBACK_CONNECT_FAIL);
//                    MessageParcel messageParcel = MessageParcel.create();
//                    messageParcel.writeString(ZSONObject.toZSONString(connectFailData));
//               senDataToRemote     startNotify(messageParcel);
//                }
                //通知js断开连接
//                case MyRemoteProxy.SEND_DISCONNECT: {
//                    HiLog.error(LABEL_LOG,"SEND_DISCONNECT");
//                    if(conn != null) {
//                        conn.onAbilityDisconnectDone(new ElementName(),0);
//                    }
//                }
                default: {
                    Map<String, Object> result = new HashMap<String, Object>();
                    result.put("abilityError", ERROR);
                    reply.writeString(ZSONObject.toZSONString(result));
                    return false;
                }
            }
            return true;
        }

        //调用事件（发布）
        private void sendEvent(String route) {
            Intent intent = new Intent();
            Operation operation = new Intent.OperationBuilder().withAction(CommonData.ROUTE_EVENT).build();
            intent.setOperation(operation);
            intent.setParam(CommonData.KEY_JS_ROUTE,route);
            CommonEventData eventData = new CommonEventData(intent);
            try {
                CommonEventManager.publishCommonEvent(eventData);
                HiLog.info(LABEL_LOG,"调用事件");
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }


        //调用js订阅的回调函数
        public void startNotify(MessageParcel data) {
            try {
                reportEvent(data);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        //调用js绑定的方法
        private void reportEvent(MessageParcel data) throws RemoteException {
            MessageParcel reply = MessageParcel.obtain();
            MessageOption option = new MessageOption();
            for (IRemoteObject item : remoteObjectHandlers) {
                item.sendRequest(100, data, reply, option);
            }
            reply.reclaim();
            data.reclaim();
        }

    }

    class MyRemoteProxy implements IRemoteBroker {
        private static final int SUCCESS = 0;

        private static final int REQUEST_START_ABILITY = 1001;

        private static final int REQUEST_SEND_DATA = 1002;

        private static final int SEND_START_FILE = 2001;

        private static final int SEND_DISCONNECT = 2002;

        private final IRemoteObject remote;

        MyRemoteProxy(IRemoteObject remote) {
            this.remote = remote;
        }

        @Override
        public IRemoteObject asObject() {
            return remote;
        }

        private void senDataToRemote(int requestType, MessageParcel sendData) throws RemoteException {
            HiLog.info(LABEL_LOG,"senDataToRemote：" + requestType);
            MessageParcel data = MessageParcel.obtain();
            MessageParcel reply = MessageParcel.obtain();

            try {
                isLocal = false;
                SendData sendDataR = new SendData();
                sendDataR.setMsg(sendData.readString());
                sendDataR.setRemoteDeviceId(localDeviceId);
                data.writeString(ZSONObject.toZSONString(sendDataR));
                data.writeBoolean(isLocal);
                MessageOption option = new MessageOption(MessageOption.TF_SYNC);
                boolean sendRes = remote.sendRequest(requestType, data, reply, option);
                HiLog.info(LABEL_LOG,"是否发送成功：" + sendRes);
                int ec = reply.readInt();
                if (ec != SUCCESS) {
                    HiLog.error(LABEL_LOG, "ec != SUCCESS RemoteException");
                }
            } catch (RemoteException e) {
                HiLog.error(LABEL_LOG, "RemoteException");
            } finally {
                data.reclaim();
                reply.reclaim();
            }
        }
    }




    @Override
    public void onBackground() {
        HiLog.error(LABEL_LOG, "BallServiceAbility::onBackground");
        super.onBackground();
    }

    @Override
    public void onStop() {
        HiLog.error(LABEL_LOG, "BallServiceAbility::onStop");
        super.onStop();
    }

    @Override
    public void onCommand(Intent intent, boolean restart, int startId) {
    }

    @Override
    public IRemoteObject onConnect(Intent intent) {
        super.onConnect(intent);
        HiLog.error(LABEL_LOG,"BallServiceAbility:onConnect");
        return remote.asObject();
    }

    @Override
    public void onDisconnect(Intent intent) {
        HiLog.error(LABEL_LOG,"BallServiceAbility:onDisconnect");
        if(conn != null) {
            conn.onAbilityDisconnectDone(new ElementName(),0);
        }
    }
}